#include "modserver.h"

static struct shm_param para2;
static int *total;                      // 指向共享内存中数据节点总个数
static modbus_set_p node_arr;           // 指向共享内存中节点缓存数组头
static uint16_t flush_flag = 0;         // 刷新标志
static uint16_t send_type = 2;          // 发送类型
static modbus_set_t *modbus_set = NULL; // 改为动态分配
static int count;                       // 数据点数量
static char mod_ip[16];                 // Modbus IP地址
static int mod_port;                    // Modbus端口号
static msgbuf_t recv_buf;               // 接收消息缓冲区
sem_t sem;
int shm_initialized = 0;

/**
 * @brief 共享内存处理函数
 * @param arg 传入Modbus实例
 */
void *shm_handle(void *arg) // 采集数据，放到共享内存中
{
    int ret = -1;
    void *node_p = NULL;
    if (!shm_initialized)
    {
        ret = shm_init(&para2, "shm_mod", MAX_NODE_SIZE);
        if (ret < 0)
        {
            fprintf(stderr, "共享内存初始化失败\n");
            return NULL;
        }
        node_p = shm_getaddr(&para2);
        shm_initialized = 1; // 标记为已初始化
    }
    node_p = shm_getaddr(&para2); // 获取共享内存地址
    if (node_p == NULL)
    {
        fprintf(stderr, "无法获取共享内存地址\n");
        return NULL;
    }
    memset(node_p, 0, MAX_NODE_SIZE); // 清空共享内存
    total = (int *)node_p;
    node_arr = (modbus_set_p)(node_p + sizeof(int)); // 指向共享内存中节点缓存数组头
    *total = count;

    modbus_t *mod_set_slave = (modbus_t *)arg;
    uint16_t *dest = malloc(count * sizeof(uint16_t)); // 动态分配dest
    if (dest == NULL)
    {
        perror("malloc dest");
        return NULL;
    }

    if (modbus_set_slave(mod_set_slave, 1) < 0) // 设置ＩＤ
    {
        perror("err: slave");
        free(dest);
        return NULL;
    }
    if (modbus_connect(mod_set_slave) < 0) // 建立连接
    {
        perror("err: connect");
        free(dest);
        return NULL;
    }
    while (1)
    {
        int read = modbus_read_registers(mod_set_slave, 10000, count, dest); // 读取寄存器
        if (read == -1)
        {
            perror("read:\n");
            free(dest);
            return NULL;
        }
        sem_wait(&sem); // 保护modbus_set的访问
        for (int i = 0; i < read; i++)
        {
            modbus_set[i].new_val.i_val = dest[i];
            modbus_set[i].old_val = modbus_set[i].new_val;
            printf("%d  %s  %d  %d\n", modbus_set[i].key, modbus_set[i].name, modbus_set[i].new_val.i_val, modbus_set[i].addr);
        }
        sem_post(&sem);
        printf("-----------------------------\n");
        sem_wait(&sem);
        memcpy(node_arr, modbus_set, count * sizeof(modbus_set_t));
        sem_post(&sem);
        sleep(2);
    }
    free(dest);
    modbus_close(mod_set_slave);
    modbus_free(mod_set_slave);
}

/**
 * @brief 解析JSON文件，实例化到结构体中
 * @return 0 成功，-1 失败
 */
int assignment_modbus()
{
    char json[2048] = "";
    FILE *fp = fopen(_PATH, "r"); // 创建文件指针
    if (fp == NULL)
    {
        perror("err: fopen");
        return -1;
    }

    int n = fread(json, 1, sizeof(json), fp); // 读取文件内容
    if (n < 0)
    {
        perror("err: fread");
        fclose(fp);
        return -1;
    }

    cJSON *root = cJSON_Parse(json); // 解析JSON数据
    if (root == NULL)
    {
        printf("Failed to parse JSON-------1.\n");
        fclose(fp);
        return -1;
    }

    cJSON *mb_dev = cJSON_GetObjectItem(root, "mb_dev"); // 获取mb_dev对象
    if (mb_dev == NULL)
    {
        printf("Failed to get mb_dev object---------1.\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    cJSON *addr_item = cJSON_GetObjectItem(mb_dev, "addr");
    if (addr_item == NULL)
    {
        printf("Missing addr in mb_dev\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    strncpy(mod_ip, addr_item->valuestring, sizeof(mod_ip) - 1);
    mod_ip[sizeof(mod_ip) - 1] = '\0';

    cJSON *port_item = cJSON_GetObjectItem(mb_dev, "port");
    if (port_item == NULL)
    {
        printf("Missing port in mb_dev\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    mod_port = port_item->valueint;

    cJSON *modbus = cJSON_GetObjectItem(root, "modbus");
    if (modbus == NULL)
    {
        printf("Failed to get modbus object---------1.\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    cJSON *data = cJSON_GetObjectItem(modbus, "data");
    if (data == NULL)
    {
        printf("Missing data in modbus\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }
    count = cJSON_GetArraySize(data);
    if (count <= 0)
    {
        printf("No data points found\n");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }

    modbus_set = malloc(count * sizeof(modbus_set_t));
    if (modbus_set == NULL)
    {
        perror("malloc modbus_set");
        cJSON_Delete(root);
        fclose(fp);
        return -1;
    }

    for (int i = 0; i < count; i++)
    {
        cJSON *item = cJSON_GetArrayItem(data, i);
        if (item == NULL)
        {
            printf("Failed to get item %d from data array---------1.\n", i);
            cJSON_Delete(root);
            fclose(fp);
            free(modbus_set);
            return -1;
        }
        cJSON *key_item = cJSON_GetObjectItem(item, "key");
        if (key_item == NULL)
        {
            printf("Missing key in item %d\n", i);
            cJSON_Delete(root);
            fclose(fp);
            free(modbus_set);
            return -1;
        }
        modbus_set[i].key = key_item->valueint;

        cJSON *type_item = cJSON_GetObjectItem(item, "type");
        if (type_item == NULL)
        {
            printf("Missing type in item %d\n", i);
            cJSON_Delete(root);
            fclose(fp);
            free(modbus_set);
            return -1;
        }
        modbus_set[i].type = type_item->valueint;

        cJSON *addr_item = cJSON_GetObjectItem(item, "addr");
        if (addr_item == NULL)
        {
            printf("Missing addr in item %d\n", i);
            cJSON_Delete(root);
            fclose(fp);
            free(modbus_set);
            return -1;
        }
        modbus_set[i].addr = addr_item->valueint;

        cJSON *name_item = cJSON_GetObjectItem(item, "name");
        if (name_item == NULL)
        {
            printf("Missing name in item %d\n", i);
            cJSON_Delete(root);
            fclose(fp);
            free(modbus_set);
            return -1;
        }
        strncpy(modbus_set[i].name, name_item->valuestring, sizeof(modbus_set[i].name) - 1);
        modbus_set[i].name[sizeof(modbus_set[i].name) - 1] = '\0';
    }

    cJSON_Delete(root); // 正确释放整个JSON树
    fclose(fp);         // 关闭文件指针
    return 0;
}

int main(int argc, char const *argv[])
{
    sem_init(&sem, 0, 1); // 初始化信号量
    if (assignment_modbus() < 0)
    {
        perror("Failed to assign modbus settings");
        return -1;
    }
    modbus_t *mod_set_slave = modbus_new_tcp(mod_ip, mod_port); // 创建实例
    if (mod_set_slave == NULL)
    {
        fprintf(stderr, "无法创建Modbus上下文\n");
        free(modbus_set);
        return -1;
    }
    pthread_t pid;
    pthread_create(&pid, NULL, shm_handle, (void *)mod_set_slave); // 创建共享内存线程

    while (1) // 循环接收消息
    {
        recv_buf.mtype = 2;                                                   // 设置消息类型
        if (msg_queue_recv("msg_mod", &recv_buf, sizeof(recv_buf), 0, 0) > 0) // 接收消息
        {
            sem_wait(&sem);                 // 保护modbus_set的访问
            for (int i = 0; i < count; i++) // 使用全局变量count，避免越界
            {
                if (modbus_set[i].key == recv_buf.mkey)
                {
                    if (modbus_set[i].type == TYPE_BOOL)
                        modbus_set[i].new_val.b_val = (!strcmp(recv_buf.value, "1")) ? 1 : 0; // 设置bool值
                    else if (modbus_set[i].type == TYPE_INT)
                        modbus_set[i].new_val.i_val = atoi(recv_buf.value); // 设置整形值
                    printf("接收到消息: %d %d\n", modbus_set[i].new_val.i_val, modbus_set[i].addr);
                    int rc = modbus_write_register(mod_set_slave, modbus_set[i].addr, modbus_set[i].new_val.i_val); // 写入寄存器
                    if (rc < 0)
                    {
                        perror("modbus_write_register error:");
                        sem_post(&sem);
                        free(modbus_set);
                        return -1;
                    }
                }
            }
            sem_post(&sem);
        }
        else
        {
            perror("recv error:");
            free(modbus_set);
            return -1;
        }
        memset(&recv_buf, 0, sizeof(recv_buf));
    }
    pthread_join(pid, NULL); // 等待线程结束
    free(modbus_set);
    return 0;
}